use std::collections::HashMap;
use std::result::Result;
use std::fmt::Display;
use std::io::Read;

fn main()->Result<(),UnExpectedError>{
    let mut m = HashMap::new();
    for i in 0..4 {
        m.insert(i, i);
    }

    use_wrapper(&mut m,1,1,100,"abc.txt")?;
    Ok(())
}

#[derive(Debug)]
enum UnExpectedError {
    Io(std::io::Error)
}

struct DesignError {
    ov: i32,
    nv: i32,
}

impl std::error::Error for UnExpectedError {}

impl Display for UnExpectedError {
    fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ // ???
    use self::UnExpectedError::*;
        match &self {
            Io(ref e)=>write!(f,"IO error: {}",e) // ???
        }
    }
}

impl From<std::io::Error> for UnExpectedError {
    fn from(io_error:std::io::Error)->Self {
        UnExpectedError::Io(io_error)
    }
}

// 如果k的v等于用户猜测的ov,那么将其替换成nv.如果不是,则这是DesignError; 无论上述哪种情况发生,都打印相关信息
// 本函数内还会由路径读取一个文件,如果有则打印读取到的内容,如果没有这是严重的io错误
fn maybe_err(m: &mut HashMap<i32, i32>, k: i32, ov: i32, nv: i32, path: &str) -> Result<Result<(), DesignError>, UnExpectedError>
{
    use std::fs::File;
    // 先整致命错误
    let mut s = String::new();
    File::open(path)?.read_to_string(&mut s)?;
    println!("{}", s);


    // 再整DesignError
    if *m.get(&k).unwrap() == ov {
        m.insert(k,nv);
    }else {
        return Ok(Err(DesignError{ov,nv}))
    };

    Ok(Ok(()))
}

fn use_wrapper(m: &mut HashMap<i32, i32>, k: i32, ov: i32, nv: i32, path: &str)->Result<(),UnExpectedError> {
    match maybe_err(m,k,ov,nv,path)? {
        Ok(())=>println!("{}","It worked!"),
        // 如果写成ov:ref cur, 那么cur绑定的就是传进来的那个DesignError的ov值的引用
        // 当然也可以写成ov:ref ov, Rust会提示直接写成 ref ov更好
        // 这里只能用ref,而不能用&,因为ref就是用来干这个事的:进行模式匹配时,无论是let还是match,ref关键字可以用来创建 结构体/元组 的字段的引用
        Err(DesignError{ref ov,nv:_})=> {
            println!("The actual current value is {}",ov)
        }
    }

    Ok(())
}